package com.frame.work.rabbitmq;

import com.frame.work.common.util.DistributedLink;
import com.frame.work.lib.FrameProcessor;
import com.frame.work.lib.GatewayTimedHandle;
import com.frame.work.lib.GroupRespondHandle;
import com.rabbitmq.client.Channel;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.messaging.handler.annotation.Headers;
import org.springframework.stereotype.Component;

import java.util.Map;

/**
 * rabbit 消费者进行数据接收处理
 *
 * @author wjming
 */
@Component
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
@Slf4j
public class FrameWorkListen {
    private final RedisTemplate redisTemplate;

    private final GroupRespondHandle groupRespondHandle;

    private final FrameProcessor frameProcessor;
    private final GatewayTimedHandle gatewayTimedHandle;

    /**
     * 消息处理
     */
    @RabbitListener(queues = "${topic.rabbit.smartHomeFrameProcess}")
    public void frameDeal(Map<String, Object> frameAndChannel, Channel rabbitChannel, @Headers Map<String, Object> headers) {

        RabbitmqEnum action = RabbitmqEnum.RETRY;
        String frame = "";
        String gatewayMac = "";
        String clientIp = "";
        try {
            frame = (String) frameAndChannel.get("frame");
            String channel = (String) frameAndChannel.get("channelLongId");
            String traceId = (String) frameAndChannel.get("traceId");
            DistributedLink.putTraceId(traceId);
            Object GatewayChannelRelation = redisTemplate.opsForValue().get(channel);
            if (GatewayChannelRelation == null) {
                return;
            }
            Map<String, Object> gatewayAndChannelRelation = (Map<String, Object>) GatewayChannelRelation;
            gatewayMac = (String) gatewayAndChannelRelation.get("gatewayMac");
            clientIp = (String) gatewayAndChannelRelation.get("clientIp");
            String dataType;
            String ff = "FF";
            if (ff.equalsIgnoreCase(StringUtils.substring(frame, 2, 4))) {
                dataType = StringUtils.substring(frame, 6, 8);
            } else {
                dataType = StringUtils.substring(frame, 4, 6);
            }
            switch (dataType) {
                //群组配置回应
                case "52":
                    groupRespondHandle.processFrame(gatewayMac, frame);
                    break;
                //群组延时命令
                case "53":
                    groupRespondHandle.delayTimeDeal(gatewayMac, frame);
                    break;
                case "54":
                    gatewayTimedHandle.processFrame(gatewayMac, frame);
                    break;
                default:
                    frameProcessor.processFrame(gatewayMac, frame, channel,clientIp);
                    break;
            }
            action = RabbitmqEnum.ACCEPT;

        } catch (Exception e) {
            log.error("异常丢弃的数据:[frameDeal] -> [gatewayMac:{} frame:{}] ->[Exception: {}]", gatewayMac, frame, e.getCause());
            action = RabbitmqEnum.REJECT;
        } finally {
            try {
                //通过finally块来保证ACK/NACK会执行一次
                if (action.equals(RabbitmqEnum.ACCEPT)) {
                    rabbitChannel.basicAck((Long) headers.get(AmqpHeaders.DELIVERY_TAG), true);
                } else if (action.equals(RabbitmqEnum.RETRY)) {
                    rabbitChannel.basicNack((Long) headers.get(AmqpHeaders.DELIVERY_TAG), false, true);
                } else {
                    rabbitChannel.basicNack((Long) headers.get(AmqpHeaders.DELIVERY_TAG), false, false);
                }

            } catch (Exception e) {
                log.error("rabbitmq回应应答失败[errorBasicNack] -> [gatewayMac:{} frame:{}] ->[Exception: {}]", gatewayMac, frame, e.getCause());
            }
        }
        return;
    }
}
